1551. Mötərizələrin düzümünü nizamlamaq

 

Verilmiş mötərizələr sətrində ən az sayda mötərizənin yerini elə dəyişmək lazımdır ki, nəticədə düzgün ifadə alınsan. Əlavə etmək və ya qoşmaq olmaz..

Cəmi üç növ: adi -(), kvadrat -[] fiqurlu -{} mötərizədən istifadə olunur. Hər mötərizə cütü açılan ('(', '[', '{' ) və bağlanan (')', ']', '}') simvollardan ibarət olur.

Düzgün yə aşağıdakı kimi tərif verək:

·        Boş ifadə -düzgündür.

·        Əgər s düzgündürsə, onda (S), [S] {s} -də düzgündür.

·        Əgər s və t ifadəəri düzgündürsə, onda st –də düzgündür

Məsələn,  "([{}])", "" və "(){}[]" sətirləri düzgündür, lakin, "([}]", "([)]" və "{" yox.

Verilmiş mötərizələr sətrində ən az sayda mötərizənin yerini elə dəyişmək lazımdır ki, nəticədə düzgün ifadə alınsan.

 

Giriş. Hər sətirdə cüt sayda '(', ')', '[', ']' '{', '}' simvolları var. Hər sətrin uzunluğu 50 –dən çox deyil.

 

Çıxış. Hər sətir üçün dəyişiləcək simvolların minimal sayı çıxarılır.

 

Girişə nümunə

([{}])()[]{}

([)]

([{}[]

 

Çıxışa nümunə

0

2

1

 

 

Həlli

Dinamik proqramlama

 

Alqoritmin analizi

sisi+1sj-1sj alt sətrinin düzgün olması üçün dəyişiləcək simvolların ən az sayını f(i, j) götürək.  O zaman:

1. f(i, j) = 0 , i > j olarsa, çünki bu halda alt sətir boşdur.

2. f(i, j) = f(i + 1, j – 1) + enc(si ,sj). Elə edək ki, si simvolu açılan,  sj  isə ona müvafiq bağlanan mötərizə olsun.

Daha sonra rekursiv olaraq si+1sj-1 alt sətrinə baxırıq.

enc(si ,sj) funksiyası:

à) si simvolu açılan,  sj  isə ona müvafiq bağlanan mötərizə olduqda 0 verir.;

á) si simvolu bağlanan,  sj  isə ona müvafiq açılan mötərizə olduqda 2 verir;

â) Dihər hallarda isə 1 verir. Bu halda si və ya sj simvollarından birini dəyişmək olar ki, onlar düzgün cüt olsun.

3. f(i, j) = (f(i, k) + f(k + 1, j)).  sisi+1sj-1sj  alt sətrinə iki düzgün sisk sk+1sj.mötərizə strukturunun ardıcıllığı kimi baxırıq. sisk alt sətrinin uzunluğu cütdür, demək k , i + 1, i + 3, …, j – 2 qiymətləri alır. .

 

Alqoritmin realizə olunması

m massivinin m[i][j] elementi f(i, j).qiymətinə bərabərdir. Girişi s massivinə veririk..

 

int m[51][51], res;

char s[51];

 

enc(c, d).funksiyasını realizə edirik.

 

int enc(char c, char d)

{

  string p = "([{)]}";

 

Əgər c bağlanan, d isə açılan mötərizə olarsa onda funksiya 2 cavabı verər..

 

  if (p.find(c) / 3 > 0 && p.find(d) / 3 < 1) return 2;

 

Əgər c d müvafiq mötərizələr isə onda cavab 0 olar. Əgər onlar düzgün yerləşməyibsə onda funksiya əvvəlki sətirdə 2 cavabı verir.

 

  if (p.find(c) % 3 == p.find(d) % 3 && c != d) return 0;

 

Bütün qalan hallarda 1 verilir.

 

  return 1;

}

 

f(i, j) funksiyası sisi+1sj-1sj alt sətrini düzgün formaya gətirmək üçün lazım olan simvolların minimal sayını verir.

 

int f(int i, int j)

{

  int k;

  if (i > j) return 0;

  if (m[i][j] >= 0) return m[i][j];

  int r = f(i+1,j-1) + enc(s[i],s[j]);

  for(k = i + 1; k < j; k += 2)

    r = min(r,f(i,k) + f(k+1,j));

  return m[i][j] = r;

}

 

Proqramın əsas hissəsi. Cavab f(0, |s| – 1) olar. Burada s – giriş sətirdir..

 

while(gets(s))

{

  memset(m,-1,sizeof(m)); 

  res = f(0,strlen(s) - 1);

  printf("%d\n",res);

}